#include "PrecompiledHeaders.h"
#include "Level.h"
#include "DotSceneLoader.h"
#include "PlayState.h"
#include "ReplayState.h"

Level::Level()
{
    scene_manager = NULL;
} 

Level::Level(Ogre::String n) : name(n)
{
	seconds_for_level = 0;
	loaded = false;
	resource_type = "";
	resource_location = "";
	locked = true;
	bonus = false;
}

/*
 * Initialise the level data based on a config file
 */
void Level::init(Ogre::ConfigFile::SettingsMultiMap *settings)
{
	Ogre::ConfigFile::SettingsMultiMap::iterator i;
	Ogre::String res_folder (Constants::RESOURCES_FOLDER);
	scene_file = "";

    for (i = settings->begin(); i != settings->end(); ++i)
    {
		Ogre::String settingName = i->first;
		if (settingName == "SceneFile")
			scene_file = res_folder + i->second;
		else if (settingName == "ResourceType")
			resource_type = i->second;
		else if (settingName == "ResourceLocation")
			resource_location = res_folder + i->second;
		else if (settingName == "Timer")
			seconds_for_level = atoi(i->second.c_str());
		else if (settingName == "NormalImage")
			normal_image = i->second;
		else if (settingName == "HoverImage")
			hover_image = i->second;
		else if (settingName == "LevelName")
			level_name = i->second;
	    else if (settingName == "Bonus") {
			if(i->second == "true") {
			    bonus = true;
			}
	    }
    }

	if (scene_file == "" || resource_location == "" || resource_type == "" || seconds_for_level == 0)
		throw new Ogre::Exception(9001, "Incomplete level definition for level '" + name + "'", "LevelResources");

}



/*
 * Load the level
 */
 OgreNewt::World *Level::load(Ogre::SceneManager *s_m, Configuration *config, std::string material)
{
    scene_manager = s_m;
    initialiseOgreNewt();
    main_player = NULL;
	Ogre::DotSceneLoader scene_loader;
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation(resource_location, resource_type, name);
	Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup(name);
	if (!scene_loader.parseDotScene(this))
	    throw new Ogre::Exception(9002, "Error parsing scene", "Level::load");
	scene_manager->setSkyBox(true, material, 5000, true, Ogre::Quaternion(), name);
    loaded = true;
    return world;
}

void Level::initialiseOgreNewt()
{
    world = new OgreNewt::World();
    
    material_pairs.push_back(new OgreNewt::MaterialPair(world, world->getDefaultMaterialID(), world->getDefaultMaterialID()));
    
	default_physics = new DefaultPhysics();
	material_pairs[mpDEFAULT]->setContactCallback(default_physics);
    
    /*
    for (int i=0; i < miNUM; i++) {
        material_ids.push_back(new OgreNewt::MaterialID(world));
    }
    
    material_pairs.push_back(new OgreNewt::MaterialPair(world, world->getDefaultMaterialID(), world->getDefaultMaterialID()));
    material_pairs.push_back(new OgreNewt::MaterialPair(world, material_ids[miBALL],     material_ids[miBALL]));
    material_pairs.push_back(new OgreNewt::MaterialPair(world, material_ids[miBALL],     world->getDefaultMaterialID()));
    material_pairs.push_back(new OgreNewt::MaterialPair(world, material_ids[miTELEPORT], material_ids[miBALL]));
    material_pairs.push_back(new OgreNewt::MaterialPair(world, material_ids[miGOAL],     material_ids[miBALL]));
    material_pairs.push_back(new OgreNewt::MaterialPair(world, material_ids[miPICKUP],   material_ids[miBALL]));

	default_physics = new DefaultPhysics();
	material_pairs[mpDEFAULT]->setContactCallback(default_physics);
	*/
    
}

void Level::setMainPlayer(Player *player)
{
    main_player = player;
    
    
    
    /*
    if (main_player->getBall())
    {
        material_pairs[mpBALL_BALL]->setContactCallback(main_player->getBall());
        material_pairs[mpBALL_WORLD]->setContactCallback(main_player->getBall());
        material_pairs[mpGOAL_BALL]->setContactCallback(main_player->getBall());
    }
    
    if (main_player->getTeleportControl())
        material_pairs[mpTELEPORT_BALL]->setContactCallback(main_player->getTeleportControl());
                
    if (main_player->getPickupControl())
        material_pairs[mpPICKUP_BALL]->setContactCallback(main_player->getPickupControl());
        
        
    int first_mobj_mid = (int)material_ids.size();
    std::vector<MovingObject*>::iterator it;
    for (it = main_player->getMovingObjects()->begin(); it != main_player->getMovingObjects()->end(); it++)
    {
        OgreNewt::MaterialID *mat_id = new OgreNewt::MaterialID(world);
        (*it)->setMaterialID(mat_id);
        
        OgreNewt::MaterialPair *ball_mp = new OgreNewt::MaterialPair(world, mat_id, material_ids[miBALL]);
        OgreNewt::MaterialPair *self_mp = new OgreNewt::MaterialPair(world, mat_id, mat_id);
        OgreNewt::MaterialPair *world_mp = new OgreNewt::MaterialPair(world, mat_id, world->getDefaultMaterialID());
                
        ball_mp->setContactCallback(*it);
        self_mp->setContactCallback(*it);
        world_mp->setContactCallback(*it);
        
        material_ids.push_back(mat_id);
        material_pairs.push_back(ball_mp);
        material_pairs.push_back(self_mp);
        material_pairs.push_back(world_mp);
        
        std::vector<OgreNewt::MaterialID*>::iterator mid_it, start, end;
        start = material_ids.begin() + first_mobj_mid;
        end = material_ids.end() - 1;
        for(mid_it = start; mid_it != end; mid_it ++)
        {
            OgreNewt::MaterialPair *mp = new OgreNewt::MaterialPair(world, mat_id, *mid_it);
            mp->setContactCallback(*it);
            material_pairs.push_back(mp);
        }
    }*/
}

/*
 * Unload the level
 */
void Level::unload()
{
    delete world;
    
    std::vector<Pickup*>::iterator it;
    for (it = pickups.begin(); it != pickups.end(); it++)
        delete *it;
    pickups.clear();
        
    std::vector<OgreNewt::MaterialID*>::iterator it2;
    for (it2 = material_ids.begin(); it2 != material_ids.end(); it2++)
        delete *it2;
    material_ids.clear();
        
    std::vector<OgreNewt::MaterialPair*>::iterator it3;
    for (it3 = material_pairs.begin(); it3 != material_pairs.end(); it3++)
        delete *it3;
    material_pairs.clear();
        
    delete default_physics;

	ReplayState::removeAllReplays();
    
    scene_manager->clearScene();
    
    Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup(name);
    Level::main_player = NULL;
    loaded = false;
    
    PlayState::removeAllPlayers();
}
